use std::{collections::HashMap, sync::Arc};

use monitor::{CompleterSuggestion, Monitor, MonitorCommand};

use super::fdinfo::{fdinfo_get, mon_fd_completer};
use crate::{DfsError, DfsResult};

struct ReadCommand;

impl ReadCommand {
    fn do_read(&self, args: &HashMap<String, String>) -> DfsResult<String> {
        let fd = args.get("fd").unwrap().parse::<u64>().map_err(|_| DfsError::InvalidArgs)?;
        let file = fdinfo_get(fd)?;
        let size = args.get("size");
        let mut buf;
        if let Some(s) = size {
            buf = String::with_capacity(s.parse::<usize>().unwrap());
        } else {
            buf = String::new();
        }

        file.read(&mut buf)?;
        Ok(buf)
    }
}

impl MonitorCommand for ReadCommand {
    fn mon_protocol_exec(&self, args: &monitor::Protocol) -> DfsResult<monitor::Protocol> {
        let buf = self.do_read(args)?;
        let mut hash = HashMap::new();
        hash.insert("data".to_string(), buf);
        Ok(hash)
    }

    fn mon_readline_arg_type(&self) -> Option<&'static str> {
        Some("fd:u64,size:usize?")
    }
    fn mon_readline_completer(&self, args: &[&str], is_space: bool) -> Option<CompleterSuggestion> {
        mon_fd_completer(args, is_space)
    }

    fn mon_readline_exec(
        &self,
        args: &HashMap<String, String>,
        printer: &monitor::MonitorPrinter,
    ) -> DfsResult<()> {
        let buf = self.do_read(args)?;
        printer.print(buf);
        Ok(())
    }

    fn mon_readline_help(&self) -> String {
        String::from("从 fd 读取数据")
    }

    fn mon_readline_long_help(&self) -> Option<String> {
        Some(String::from("read <fd> [size]"))
    }
}

pub(crate) fn monitor_command_read_register(mon: &Monitor) {
    mon.register_command("read", Arc::new(ReadCommand)).unwrap();
}
